package com.qianclass.talklive.app.view.Graffiti;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.os.Build;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.qianclass.talklive.app.activity.VideoActivity;
import com.qianclass.talklive.app.bean.Coordinates;
import com.qianclass.talklive.app.bean.GraffitiOrdermsgBean;
import com.qianclass.talklive.app.bean.GraffitiPathPage;
import com.qianclass.talklive.app.bean.TextWhiteBoardBean;
import com.qianclass.talklive.app.bean.WhiteBoardBean;
import com.qianclass.talklive.app.bean.WhiteBoardBody;
import com.qianclass.talklive.app.utils.Constant;
import com.qianclass.talklive.app.utils.DensityUtil;
import com.qianclass.talklive.app.utils.FileLogUtils;
import com.qianclass.talklive.app.utils.LogUtil;
import com.qianclass.talklive.app.utils.ThreadUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;


/**
 * Created by huangziwei on 2016/9/3.
 */
public class GraffitiView extends View {

    public static final int ERROR_INIT = -1;
    public static final int ERROR_SAVE = -2;

    private static final float VALUE = 1f;
    private final int TIME_SPAN = 80;

    private Context mContext;

    private GraffitiListener mGraffitiListener;

    private Bitmap mBitmap; // 原图
    private Bitmap mBitmapEraser; // 橡皮擦底图
    private Bitmap mGraffitiBitmap; // 用绘制涂鸦的图片
    private Canvas mBitmapCanvas;

    private float mPrivateScale; // 图片适应屏幕（mScale=1）时的缩放倍数
    private int mPrivateHeight, mPrivateWidth;// 图片在缩放mPrivateScale倍数的情况下，适应屏幕（mScale=1）时的大小（肉眼看到的在屏幕上的大小）
    private float mCentreTranX, mCentreTranY;// 图片在缩放mPrivateScale倍数的情况下，居中（mScale=1）时的偏移（肉眼看到的在屏幕上的偏移）

    private BitmapShader mBitmapShader; // 用于涂鸦的图片上!
    private BitmapShader mBitmapShaderEraser; // 橡皮擦底图
    private Path mCurrPath; // 当前手写的路径
    private Path mCurrPathTeacher; // 老师手写的路径
    private Path mTempPath;
    private CopyLocation mCopyLocation; // 仿制的定位器

    private Paint mPaint; //本地画笔设置
    private GraffitiColor mColor; // 本地画笔底色

    private Paint mPaintTeacher; // 教师画笔设置
    private GraffitiColor mColorTeacher; // 教师画笔底色

    private int mTouchMode; // 触摸模式，用于判断单点或多点触摸
    private float mPaintSize;

    private float mScale; // 图片在相对于居中时的缩放倍数 （ 图片真实的缩放倍数为 mPrivateScale*mScale ）

    private float mTransX = 0, mTransY = 0; // 图片在相对于居中时且在缩放mScale倍数的情况下的偏移量 （ 图片真实偏移量为　(mCentreTranX + mTransX)/mPrivateScale*mScale ）

    private String drawText = "";// 文本信息

/*
      明白下面一点，对于理解涂鸦坐标系很重要：
      假设不考虑任何缩放，图片就是肉眼看到的那么大，此时图片的大小width =  mPrivateWidth * mScale ,
      偏移量x = mCentreTranX + mTransX，而view的大小为width = getWidth()。height和偏移量y以此类推。
*/

    private boolean mIsPainting = false; // 是否正在绘制
    private boolean isJustDrawOriginal; // 是否只绘制原图

    private boolean mIsDrawableOutside = false; // 触摸时，图片区域外是否绘制涂鸦轨迹
    private boolean mEraserImageIsResizeable;
    private boolean mReady = false;

    private boolean isOnTouchEventDraw = false; // 正在触摸绘制
    private boolean isReceiveOrders = false;//是否是接收服务器发送的 画图形 的白板命令

    private int positionX = 50; // 指示器光标坐标
    private int positionY = 50; // 指示器光标坐标

    // 保存涂鸦操作（本地画笔）
    private CopyOnWriteArrayList<GraffitiPath> mPathStack = new CopyOnWriteArrayList<GraffitiPath>();
    // 保存涂鸦操作，便于撤销（本地画笔与PC端画笔轨迹）
    public Map<String, GraffitiPath> mPathStackBackup = new HashMap<>();
    // 涂鸦笔迹存储
    public List<GraffitiOrdermsgBean> mGraffitiOrderData = new ArrayList<>();
    //服务器返回的唯一轨迹 ID
    private int objid;
    // 记录x y
    private List<Coordinates> XYPath = new ArrayList<>();
    private Coordinates mCoordinates;
    // 颜色
    private String color = "0XFF9000";
    // 画笔集合信息
    private WhiteBoardBean mWhiteBoardBean ;
    // 记录页面轨迹
    private GraffitiPathPage mGraffitiPathPage;
    public int mTeacherCurrentPage;
    public int mRoomType;
    public boolean mAnchor;

    /**
     * 画笔
     */
    public enum Pen {
        HAND,  // 手绘
        COPY,  // 仿制
        ERASER // 橡皮擦
    }

    /**
     * 图形
     */
    public enum Shape {
        HAND_WRITE,     // 手写
        ARROW,          // 箭头
        LINE,           // 直线
        FILL_CIRCLE,    // 实心圆
        HOLLOW_CIRCLE,  // 空心圆
        FILL_RECT,      // 实心矩形
        HOLLOW_RECT,    // 空心矩形
        HOLLOW_OVAL,    // 空心椭圆
        TEXT_BOX        // 文本框
    }

    private Pen mPen;
    private Shape mShape = Shape.HAND_WRITE;

    private Shape mShapeTeacher = Shape.HAND_WRITE;

    private float mTouchDownX, mTouchDownY, mLastTouchX, mLastTouchY, mTouchX, mTouchY;
    private Matrix mShaderMatrix, mMatrixTemp;

    private float mAmplifierRadius;
    private Path mAmplifierPath;
    private float mAmplifierScale = 0; // 放大镜的倍数
    private Paint mAmplifierPaint;
    private int mAmplifierHorizonX; // 放大器的位置的x坐标，使其水平居中

    public GraffitiView(Context context, Bitmap bitmap, GraffitiListener listener) {
        this(context, bitmap,  true, listener);
    }

    /**
     * @param context
     * @param bitmap
     * @param eraserImageIsResizeable 橡皮擦底图是否调整大小，如果可以则调整到跟当前涂鸦图片一样的大小．
     * @param listener
     * @
     */
    public GraffitiView(Context context, Bitmap bitmap,  boolean eraserImageIsResizeable, GraffitiListener listener) {
        super(context);

       /* //[11,18)对硬件加速支持不完整，clipPath时会crash
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2
                && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            setLayerType(LAYER_TYPE_SOFTWARE, null);
        }*/

        mContext = context;

        // 关闭硬件加速，因为bitmap的Canvas不支持硬件加速
        if (Build.VERSION.SDK_INT >= 11) {
            setLayerType(LAYER_TYPE_SOFTWARE, null);
        }
        mBitmap = bitmap;
        mGraffitiListener = listener;
        if (mGraffitiListener == null) {
            throw new RuntimeException("GraffitiListener is null!!!");
        }
        if (mBitmap == null) {
            throw new RuntimeException("Bitmap is null!!!");
        }

        //if (eraser != null) {
        //    mBitmapEraser = ImageUtils.createBitmapFromPath(eraser, getContext());
        //}
        mEraserImageIsResizeable = eraserImageIsResizeable;

        init();

        //测试
        mCursorLocation = new CursorLocation(50,50);
    }
    CursorLocation mCursorLocation;


    public void init() {

        mScale = 1f;
        mPaintSize = 3;
        mColor = new GraffitiColor(Color.parseColor("#FF9000"));
        mPaint = new Paint();
        mPaint.setStrokeWidth(mPaintSize);
        mPaint.setColor(mColor.color);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);// 圆滑

        mColorTeacher = new GraffitiColor(Color.parseColor("#FF9000"));
        mPaintTeacher = new Paint();
        mPaintTeacher.setStrokeWidth(mPaintSize);
        mPaintTeacher.setColor(mColorTeacher.color);
        mPaintTeacher.setStyle(Paint.Style.STROKE);
        mPaintTeacher.setAntiAlias(true);
        mPaintTeacher.setStrokeJoin(Paint.Join.ROUND);
        mPaintTeacher.setStrokeCap(Paint.Cap.ROUND);// 圆滑

        mPen = Pen.HAND;
        mShape = Shape.HAND_WRITE;
        mShapeTeacher = Shape.HAND_WRITE;

        this.mBitmapShader = new BitmapShader(this.mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

        if (mBitmapEraser != null) {
            this.mBitmapShaderEraser = new BitmapShader(this.mBitmapEraser, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        } else {
            this.mBitmapShaderEraser = mBitmapShader;
        }

        mShaderMatrix = new Matrix();
        mMatrixTemp = new Matrix();
        mTempPath = new Path();
        mCopyLocation = new CopyLocation(150, 150, mPaintSize);

        mAmplifierPaint = new Paint();
        mAmplifierPaint.setColor(0xaaffffff);
        mAmplifierPaint.setStyle(Paint.Style.STROKE);
        mAmplifierPaint.setAntiAlias(true);
        mAmplifierPaint.setStrokeJoin(Paint.Join.ROUND);
        mAmplifierPaint.setStrokeCap(Paint.Cap.ROUND);// 圆滑
        mAmplifierPaint.setStrokeWidth(DensityUtil.dip2px(getContext(), 10));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        setBG();
        mCopyLocation.updateLocation(toX(w / 2), toY(h / 2));
        if (!mReady) {
            mGraffitiListener.onReady();
            mReady = true;
        }
    }


    //设置服务器白板命令操作 , 画线
    public void setDrawPaint(float stratX, float stratY, float lastX, float lastY, int size, int n,
                             int color, float paintSize, int objid)
    {

        if (n == 0) {
            setColorTeacher(color);
            mShapeTeacher = Shape.HAND_WRITE;
            mPen = Pen.HAND;
            mCurrPathTeacher = new Path();
            mCurrPathTeacher.moveTo(stratX, stratY);
            isReceiveOrders = true;
        }

        mCurrPathTeacher.quadTo(stratX, stratY, lastX, lastY);

        if (size == (n+1)){
            GraffitiPath path = GraffitiPath.toPath(mPen, mShapeTeacher, mPaintSize, mColorTeacher.copy(),
                    mCurrPathTeacher, mPen == Pen.COPY ? new Matrix(mShaderMatrix) : null);
            mPathStackBackup.put(objid+"", path);
            if (mBitmapCanvas == null) {
                initCanvas();
            }
            drawTeacher(mBitmapCanvas, path); // 保存到图片中
            postInvalidate();
        }

    }



    private float shapeLeft, shapeTop, shapeRight, shapeBottom;
    //设置服务器白板命令操作 , 画图形
    public void setDrawPaintEmptyRect(float left, float top, float right, float bottom, int color,
                                      String shapeType, String text, int objid)
    {
        mPen = Pen.HAND;
        mIsPainting = true;
        isReceiveOrders = true;
        this.shapeLeft = left;
        this.shapeTop = top;
        this.shapeRight = right;
        this.shapeBottom = bottom;
        setColorTeacher(color);
        mTouchDownX = -1;//使doDraw()方法中判断条件为 false，避免空指针；（方法中的判断语句： if (mTouchDownX == mTouchX && mTouchDownY == mTouchY && mTouchDownX == mLastTouchX && mTouchDownY == mLastTouchY)）
        if ("emptyrect".equals(shapeType)) {
            mShapeTeacher = Shape.HOLLOW_RECT; // 空心矩形
        }else if ("emptyellipse".equals(shapeType)) {
            mShapeTeacher = Shape.HOLLOW_OVAL; // 空心椭圆
        }else if ("line".equals(shapeType)){
            mShapeTeacher = Shape.LINE; // 直线
        }else if("text".equals(shapeType)) {
            mShapeTeacher = Shape.TEXT_BOX; // 添加文字
            drawText = text;
            Paint.FontMetrics fontMetrics = mPaintTeacher.getFontMetrics();
            this.shapeTop = top - fontMetrics.top;
        }
        GraffitiPath pathShape = GraffitiPath.toShape(mPen, mShapeTeacher, mPaintSize, mColorTeacher.copy(),
                shapeLeft, shapeTop, shapeRight, shapeBottom, null, drawText);
        mPathStackBackup.put(objid+"", pathShape);
        if (mBitmapCanvas == null) {
            initCanvas();
        }
        drawTeacher(mBitmapCanvas, pathShape); // 保存到图片中
        postInvalidate();

    }


    //设置服务器白板命令操作 , 添加文字
    public void setDrawPaintText(float left, float top, float right, float bottom, String text,
                                 int color, int textSize, int objid)
    {
        mPen = Pen.HAND;
        mShapeTeacher = Shape.TEXT_BOX; // 添加文字
        mTouchDownX = -1;//使doDraw()方法中判断条件为 false，避免空指针；（方法中的判断语句： if (mTouchDownX == mTouchX && mTouchDownY == mTouchY && mTouchDownX == mLastTouchX && mTouchDownY == mLastTouchY)）
        mIsPainting = true;
        isReceiveOrders = true;
        this.shapeLeft = left;
        this.shapeTop = top - 5;
        this.shapeRight = right;
        this.shapeBottom = bottom;
        //Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        //this.shapeTop = top - fontMetrics.top -10;
        drawText = text;
        mPaintTeacher.setTextSize(textSize);
        setColorTeacher(color);
        GraffitiPath pathShape = GraffitiPath.toShape(mPen, mShapeTeacher, mPaintSize, mColorTeacher.copy(),
                shapeLeft, shapeTop, shapeRight, shapeBottom, null, drawText);
        mPathStackBackup.put(objid+"", pathShape);
        if (mBitmapCanvas == null) {
            initCanvas();
        }
        drawTeacher(mBitmapCanvas, pathShape); // 保存到图片中
        postInvalidate();
    }



    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mTouchMode = 1;
                mTouchDownX = mTouchX = mLastTouchX = event.getX();
                mTouchDownY = mTouchY = mLastTouchY = event.getY();
                //setColor(Color.parseColor("#FF9000"));
                mCoordinates = new Coordinates();
                mCoordinates.setX(toX(event.getX()));
                mCoordinates.setY(toY(event.getY()));
                XYPath.clear();
                XYPath.add(mCoordinates);

                if (mPen == Pen.COPY && mCopyLocation.isInIt(toX(mTouchX), toY(mTouchY))) { // 点击copy 仿制
                    mCopyLocation.isRelocating = true;
                    mCopyLocation.isCopying = false;
                } else {
                    if (mPen == Pen.COPY) {// 点击copy 仿制
                        if (!mCopyLocation.isCopying) {
                            mCopyLocation.setStartPosition(toX(mTouchX), toY(mTouchY));
                            resetMatrix();
                        }
                        mCopyLocation.isCopying = true;
                    }
                    mCopyLocation.isRelocating = false;
                    mCurrPath = new Path();
                    mCurrPath.moveTo(toX(mTouchDownX), toY(mTouchDownY));
                    if (mShape == Shape.HAND_WRITE) { // 手写

                    } else {  // 画图形

                    }
                    mIsPainting = true;
                }
                // LogUtil.i("GraffitiView" , "ACTION_DOWN");
                invalidate();
                return true;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mTouchMode = 0;
                mLastTouchX = mTouchX;
                mLastTouchY = mTouchY;
                mTouchX = event.getX();
                mTouchY = event.getY();

                // 为了仅点击时也能出现绘图，必须移动path
                if (mTouchDownX == mTouchX && mTouchDownY == mTouchY & mTouchDownX == mLastTouchX && mTouchDownY == mLastTouchY) {
                    mTouchX += VALUE;
                    mTouchY += VALUE;
                }

                if (mCopyLocation.isRelocating) { // 正在定位location
                    mCopyLocation.updateLocation(toX(mTouchX), toY(mTouchY));
                    mCopyLocation.isRelocating = false;
                } else {
                    if (mIsPainting) {

                        if (mPen == Pen.COPY) {
                            mCopyLocation.updateLocation(mCopyLocation.mCopyStartX + toX(mTouchX) - mCopyLocation.mTouchStartX,
                                    mCopyLocation.mCopyStartY + toY(mTouchY) - mCopyLocation.mTouchStartY);
                        }

                        GraffitiPath path = null;

                        // 把操作记录到加入的堆栈中
                        if (mShape == Shape.HAND_WRITE) { // 手写
                            mCurrPath.quadTo(
                                    toX(mLastTouchX),
                                    toY(mLastTouchY),
                                    toX((mTouchX + mLastTouchX) / 2),
                                    toY((mTouchY + mLastTouchY) / 2));
                            path = GraffitiPath.toPath(mPen, mShape, mPaintSize, mColor.copy(), mCurrPath, mPen == Pen.COPY ? new Matrix(mShaderMatrix) : null);
                        } else {  // 画图形
                            path = GraffitiPath.toShape(mPen, mShape, mPaintSize, mColor.copy(),
                                    toX(mTouchDownX), toY(mTouchDownY), toX(mTouchX), toY(mTouchY),
                                    mPen == Pen.COPY ? new Matrix(mShaderMatrix) : null, null);
                        }


                        mCoordinates = new Coordinates();
                        mCoordinates.setX(toX(event.getX()));
                        mCoordinates.setY(toY(event.getY()));
                        XYPath.add(mCoordinates);

                        int random = new Random().nextInt();
                        postDrawLineData(Math.abs(random));
                        mPathStackBackup.put(Math.abs(random)+"", path);
                        mPathStack.add(path);
                        draw(mBitmapCanvas, path); // 保存到图片中
                        mIsPainting = false;
                    }
                }
                // LogUtil.i("GraffitiView" , "ACTION_CANCEL");
                invalidate();
                return true;
            case MotionEvent.ACTION_MOVE:
                if (mTouchMode < 2) { // 单点滑动
                    isOnTouchEventDraw = true;
                    mLastTouchX = mTouchX;
                    mLastTouchY = mTouchY;
                    mTouchX = event.getX();
                    mTouchY = event.getY();

                    if (mCopyLocation.isRelocating) { // 正在定位location
                        mCopyLocation.updateLocation(toX(mTouchX), toY(mTouchY));
                    } else {
                        if (mPen == Pen.COPY) {// 仿制
                            mCopyLocation.updateLocation(mCopyLocation.mCopyStartX + toX(mTouchX) - mCopyLocation.mTouchStartX,
                                    mCopyLocation.mCopyStartY + toY(mTouchY) - mCopyLocation.mTouchStartY);
                        }
                        if (mShape == Shape.HAND_WRITE) { // 手写
                            mCurrPath.quadTo(
                                    toX(mLastTouchX),
                                    toY(mLastTouchY),
                                    toX((mTouchX + mLastTouchX) / 2),
                                    toY((mTouchY + mLastTouchY) / 2));

                            mCoordinates = new Coordinates();
                            mCoordinates.setX(toX(event.getX()));
                            mCoordinates.setY(toY(event.getY()));
                            XYPath.add(mCoordinates);

                            if (XYPath.size() == 200) {
                                GraffitiPath path = GraffitiPath.toPath(mPen, mShape, mPaintSize, mColor.copy(), mCurrPath, mPen == Pen.COPY ? new Matrix(mShaderMatrix) : null);
                                int random = new Random().nextInt();
                                postDrawLineData(random);
                                mPathStackBackup.put(random+"", path);
                                mPathStack.add(path);
                                draw(mBitmapCanvas, path); // 保存到图片中
                                mIsPainting = false;
                                invalidate();
                                return true;
                            }
                            // 当为手绘时，一条轨迹的长度限制在200个坐标点
                            if (XYPath.size() > 200) {
                                return true;
                            }
                        } else { // 画图形

                        }
                    }
                } else { // 多点

                }
                // LogUtil.i("GraffitiView" , "ACTION_MOVE");
                invalidate();
                return true;
            case MotionEvent.ACTION_POINTER_UP:
                mTouchMode -= 1;
                // LogUtil.i("GraffitiView" , "ACTION_POINTER_UP");
                invalidate();
                return true;
            case MotionEvent.ACTION_POINTER_DOWN:
                mTouchMode += 1;
                // LogUtil.i("GraffitiView" , "ACTION_POINTER_DOWN");
                invalidate();
                return true;
        }
        return super.onTouchEvent(event);
    }


    private void setBG() {// 不用resize preview
        int w = mBitmap.getWidth();
        int h = mBitmap.getHeight();
        float nw = w * 1f / getWidth();
        float nh = h * 1f / getHeight();
        if (nw > nh) {
            mPrivateScale = 1 / nw;
            mPrivateWidth = getWidth();
            mPrivateHeight = (int) (h * mPrivateScale);
        } else {
            mPrivateScale = 1 / nh;
            mPrivateWidth = (int) (w * mPrivateScale);
            mPrivateHeight = getHeight();
        }
        // 使图片居中
        mCentreTranX = (getWidth() - mPrivateWidth) / 2f;
        mCentreTranY = (getHeight() - mPrivateHeight) / 2f;

        initCanvas();
        resetMatrix();

        mAmplifierRadius = Math.min(getWidth(), getHeight()) / 4;
        mAmplifierPath = new Path();
        mAmplifierPath.addCircle(mAmplifierRadius, mAmplifierRadius, mAmplifierRadius, Path.Direction.CCW);
        mAmplifierHorizonX = (int) (Math.min(getWidth(), getHeight()) / 2 - mAmplifierRadius);

        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        // LogUtil.i("GraffitiView" , "@Override-onDraw");
        if (mBitmap.isRecycled() || mGraffitiBitmap.isRecycled()) {
            return;
        }

        canvas.save();
        doDraw(canvas);
        canvas.restore();

        if (mAmplifierScale > 0) { //启用放大镜
            canvas.save();

            if (mTouchY <= mAmplifierRadius * 2) { // 在放大镜的范围内， 把放大镜仿制底部
                canvas.translate(mAmplifierHorizonX, getHeight() - mAmplifierRadius * 2);
            } else {
                canvas.translate(mAmplifierHorizonX, 0);
            }
            canvas.clipPath(mAmplifierPath);
            canvas.drawColor(0xFFEBEBEB);

            canvas.save();
            float scale = mAmplifierScale / mScale; // 除以mScale，无论当前图片缩放多少，都产生图片在居中状态下缩放mAmplifierScale倍的效果
            canvas.scale(scale, scale);
            canvas.translate(-mTouchX + mAmplifierRadius / scale, -mTouchY + mAmplifierRadius / scale);
            doDraw(canvas);
            canvas.restore();

            // 画放大器的边框
            DrawUtil.drawCircle(canvas, mAmplifierRadius, mAmplifierRadius, mAmplifierRadius, mAmplifierPaint);
            canvas.restore();
        }

    }

    private void doDraw(Canvas canvas) {
        // LogUtil.i("GraffitiView" , "@Override-onDraw-doDraw");
        float left = (mCentreTranX + mTransX) / (mPrivateScale * mScale);
        float top = (mCentreTranY + mTransY) / (mPrivateScale * mScale);
        // 画布和图片共用一个坐标系，只需要处理屏幕坐标系到图片（画布）坐标系的映射关系
        canvas.scale(mPrivateScale * mScale, mPrivateScale * mScale); // 缩放画布
        canvas.translate(left, top); // 偏移画布

        if (!mIsDrawableOutside) { // 裁剪绘制区域为图片区域
            canvas.clipRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
        }

        if (isJustDrawOriginal) { // 只绘制原图
            canvas.drawBitmap(mBitmap, 0, 0, null);
            return;
        }

        // 绘制涂鸦
        canvas.drawBitmap(mGraffitiBitmap, 0, 0, null);

        if (mIsPainting) {  //画在view的画布上
            Path path;
            float span = 0;
            // 为了仅点击时也能出现绘图，必须移动path
            if (mTouchDownX == mTouchX && mTouchDownY == mTouchY && mTouchDownX == mLastTouchX && mTouchDownY == mLastTouchY) {
                mTempPath.reset();
                mTempPath.addPath(mCurrPath);
                mTempPath.quadTo(
                        toX(mLastTouchX),
                        toY(mLastTouchY),
                        toX((mTouchX + mLastTouchX + VALUE) / 2),
                        toY((mTouchY + mLastTouchY + VALUE) / 2));
                path = mTempPath;
                span = VALUE;
            } else {
                path = mCurrPath;
                span = 0;
            }
            // 画触摸的路径
            mPaint.setStrokeWidth(mPaintSize);

            // 画图形 、文字 (接收服务器白板命令 画图形)
            if(isReceiveOrders) {
                if (mShapeTeacher == Shape.HAND_WRITE) { //手写
                    draw(canvas, mPen, mPaintTeacher, mCurrPathTeacher, mShaderMatrix, mColorTeacher);
                }else if (mShapeTeacher == Shape.TEXT_BOX) {// 添加文本 文字
                    draw(canvas, mPen, mShapeTeacher, mPaintTeacher, shapeLeft, shapeTop, shapeRight, shapeBottom,
                                mShaderMatrix, mColorTeacher, drawText);
                } else {// 画图形
                    draw(canvas, mPen, mShapeTeacher, mPaintTeacher, shapeLeft, shapeTop, shapeRight, shapeBottom,
                            mShaderMatrix, mColorTeacher, null);
                }
                isReceiveOrders = false;

            }else if(isOnTouchEventDraw){ // 学生端 （本地触摸进行绘画）
                if (mShape == Shape.HAND_WRITE) { //手写
                    draw(canvas, mPen, mPaint, path, mShaderMatrix, mColor);
                }else if (mShape == Shape.TEXT_BOX) {// 添加文本 文字
                    draw(canvas, mPen, mShape, mPaint, shapeLeft, shapeTop, shapeRight, shapeBottom,
                            mShaderMatrix, mColor, drawText);
                } else {// 画图形
                    draw(canvas, mPen, mShape, mPaint, toX(mTouchDownX), toY(mTouchDownY),
                            toX(mTouchX + span), toY(mTouchY + span), mShaderMatrix, mColor, null);
                }
                isOnTouchEventDraw = false;
            }
        }

        if (mPen == Pen.COPY) {
            mCopyLocation.drawItSelf(canvas);
        }
        // 指示器光标
        drawPosition(canvas, positionX, positionY);
    }

    private void draw(Canvas canvas, Pen pen, Paint paint, Path path, Matrix matrix, GraffitiColor color) {
        resetPaint(pen, paint, matrix, color);

        paint.setStyle(Paint.Style.STROKE);
        canvas.drawPath(path, paint);

    }

    private void draw(Canvas canvas, Pen pen, Shape shape, Paint paint, float sx, float sy, float dx, float dy,
                      Matrix matrix, GraffitiColor color, String text ) {
        resetPaint(pen, paint, matrix, color);

        paint.setStyle(Paint.Style.STROKE);

        switch (shape) { // 绘制图形
            case ARROW:
                paint.setStyle(Paint.Style.FILL);
                DrawUtil.drawArrow(canvas, sx, sy, dx, dy, paint);
                break;
            case LINE:
                DrawUtil.drawLine(canvas, sx, sy, dx, dy, paint);
                break;
            case FILL_CIRCLE:
                paint.setStyle(Paint.Style.FILL);
            case HOLLOW_CIRCLE:
                DrawUtil.drawCircle(canvas, sx, sy,
                        (float) Math.sqrt((sx - dx) * (sx - dx) + (sy - dy) * (sy - dy)), paint);
                break;
            case FILL_RECT:
                paint.setStyle(Paint.Style.FILL);
            case HOLLOW_RECT:
                DrawUtil.drawRect(canvas, sx, sy, dx, dy, paint);
                break;
            case HOLLOW_OVAL:
                DrawUtil.drawOval(canvas, sx, sy, dx, dy, paint);
                break;
            case TEXT_BOX:
                DrawUtil.drawText(canvas, sx, sy, text , paint);
                break;
            default:
                throw new RuntimeException("unknown shape:" + shape);
        }
    }


    private void draw(Canvas canvas, CopyOnWriteArrayList<GraffitiPath> pathStack) {
        // 还原堆栈中的记录的操作
        for (GraffitiPath path : pathStack) {
            draw(canvas, path);
        }
    }

    private void draw(Canvas canvas, Map<String, GraffitiPath> pathStack) {
        // 还原堆栈中的记录的操作
        Iterator iter = pathStack.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, GraffitiPath> entry = (Map.Entry<String, GraffitiPath>) iter.next();
            GraffitiPath path = entry.getValue();
            draw(canvas, path);
        }
    }


    private void draw(Canvas canvas, GraffitiPath path) {
        mPaint.setStrokeWidth(path.mStrokeWidth);
        if (path.mShape == Shape.HAND_WRITE) { // 手写
            draw(canvas, path.mPen, mPaint, path.mPath, path.mMatrix, path.mColor);
        } else if (path.mShape == Shape.TEXT_BOX){ // 输入文字
            draw(canvas, path.mPen, path.mShape, mPaint,
                    path.mSx, path.mSy, path.mDx, path.mDy, path.mMatrix, path.mColor, path.text);
        }else { // 画图形
            draw(canvas, path.mPen, path.mShape, mPaint,
                    path.mSx, path.mSy, path.mDx, path.mDy, path.mMatrix, path.mColor, null);
        }
    }


    private void drawTeacher(Canvas canvas, GraffitiPath path) {
        mPaintTeacher.setStrokeWidth(path.mStrokeWidth);
        if (path.mShape == Shape.HAND_WRITE) { // 手写
            draw(canvas, path.mPen, mPaintTeacher, path.mPath, path.mMatrix, path.mColor);
        } else if (path.mShape == Shape.TEXT_BOX){ // 输入文字
            draw(canvas, path.mPen, path.mShape, mPaintTeacher,
                    path.mSx, path.mSy, path.mDx, path.mDy, path.mMatrix, path.mColor, path.text);
        }else { // 画图形
            draw(canvas, path.mPen, path.mShape, mPaintTeacher,
                    path.mSx, path.mSy, path.mDx, path.mDy, path.mMatrix, path.mColor, null);
        }
    }

    private void resetPaint(Pen pen, Paint paint, Matrix matrix, GraffitiColor color) {
        switch (pen) { // 设置画笔
            case HAND:
                paint.setShader(null);
                color.initColor(paint, null);
                break;
            case COPY:
                // 调整copy图片位置
                mBitmapShader.setLocalMatrix(matrix);
                paint.setShader(this.mBitmapShader);
                break;
            case ERASER:
                if (mBitmapShader == mBitmapShaderEraser) { // 图片的矩阵不需要任何偏移
                    mBitmapShaderEraser.setLocalMatrix(null);
                }
                paint.setShader(this.mBitmapShaderEraser);
                break;
        }
    }


    /**
     * 将屏幕触摸坐标x转换成在图片中的坐标
     */
    public final float toX(float touchX) {
        return (touchX - mCentreTranX - mTransX) / (mPrivateScale * mScale);
    }

    /**
     * 将屏幕触摸坐标y转换成在图片中的坐标
     */
    public final float toY(float touchY) {
        return (touchY - mCentreTranY - mTransY) / (mPrivateScale * mScale);
    }

    /**
     * 坐标换算
     * （公式由toX()中的公式推算出）
     *
     * @param touchX    触摸坐标
     * @param graffitiX 在涂鸦图片中的坐标
     * @return 偏移量
     */
    public final float toTransX(float touchX, float graffitiX) {
        return -graffitiX * (mPrivateScale * mScale) + touchX - mCentreTranX;
    }

    public final float toTransY(float touchY, float graffitiY) {
        return -graffitiY * (mPrivateScale * mScale) + touchY - mCentreTranY;
    }


    private void initCanvas() {
        if (mGraffitiBitmap != null) {
            mGraffitiBitmap.recycle();
        }
        //图片画布
        mGraffitiBitmap = mBitmap.copy(Bitmap.Config.RGB_565, true);
        mBitmapCanvas = new Canvas(mGraffitiBitmap);
    }

    private void resetMatrix() {
        if (mPen == Pen.COPY) { // 仿制，加上mCopyLocation记录的偏移
            this.mShaderMatrix.set(null);
            this.mShaderMatrix.postTranslate(mCopyLocation.mTouchStartX - mCopyLocation.mCopyStartX, mCopyLocation.mTouchStartY - mCopyLocation.mCopyStartY);
            this.mBitmapShader.setLocalMatrix(this.mShaderMatrix);
        } else {
            this.mShaderMatrix.set(null);
            this.mBitmapShader.setLocalMatrix(this.mShaderMatrix);
        }

        // 如果使用了自定义的橡皮擦底图，则需要调整矩阵
        if (mPen == Pen.ERASER && mBitmapShader != mBitmapShaderEraser) {
            mMatrixTemp.reset();
            mBitmapShaderEraser.getLocalMatrix(mMatrixTemp);
            mBitmapShader.getLocalMatrix(mMatrixTemp);
            // 缩放橡皮擦底图，使之与涂鸦图片大小一样
            if (mEraserImageIsResizeable) {
                mMatrixTemp.preScale(mBitmap.getWidth() * 1f / mBitmapEraser.getWidth(), mBitmap.getHeight() * 1f / mBitmapEraser.getHeight());
            }
            mBitmapShaderEraser.setLocalMatrix(mMatrixTemp);
        }
    }

    /**
     * 调整图片位置
     *
     * 明白下面一点很重要：
     * 假设不考虑任何缩放，图片就是肉眼看到的那么大，此时图片的大小width =  mPrivateWidth * mScale ,
     * 偏移量x = mCentreTranX + mTransX，而view的大小为width = getWidth()。height和偏移量y以此类推。
     */
    private void judgePosition() {
        boolean changed = false;
        if (mPrivateWidth * mScale < getWidth()) { // 限制在view范围内
            if (mTransX + mCentreTranX < 0) {
                mTransX = -mCentreTranX;
                changed = true;
            } else if (mTransX + mCentreTranX + mPrivateWidth * mScale > getWidth()) {
                mTransX = getWidth() - mCentreTranX - mPrivateWidth * mScale;
                changed = true;
            }
        } else { // 限制在view范围外
            if (mTransX + mCentreTranX > 0) {
                mTransX = -mCentreTranX;
                changed = true;
            } else if (mTransX + mCentreTranX + mPrivateWidth * mScale < getWidth()) {
                mTransX = getWidth() - mCentreTranX - mPrivateWidth * mScale;
                changed = true;
            }
        }
        if (mPrivateHeight * mScale < getHeight()) { // 限制在view范围内
            if (mTransY + mCentreTranY < 0) {
                mTransY = -mCentreTranY;
                changed = true;
            } else if (mTransY + mCentreTranY + mPrivateHeight * mScale > getHeight()) {
                mTransY = getHeight() - mCentreTranY - mPrivateHeight * mScale;
                changed = true;
            }
        } else { // 限制在view范围外
            if (mTransY + mCentreTranY > 0) {
                mTransY = -mCentreTranY;
                changed = true;
            } else if (mTransY + mCentreTranY + mPrivateHeight * mScale < getHeight()) {
                mTransY = getHeight() - mCentreTranY - mPrivateHeight * mScale;
                changed = true;
            }
        }
        if (changed) {
            resetMatrix();
        }
    }



    // ============================== api ==================================


    /**
     * WhiteBoardBean 画笔教材集合信息
     */
    public void setWhiteBoardBeanInfo(WhiteBoardBean mWhiteBoardBean) {
        this.mWhiteBoardBean = mWhiteBoardBean;
    }



    /**
     * 本地画笔清屏
     */
    public void clear() {
        mPathStack.clear();
        //mPathStackBackup.clear();
        initCanvas();
        invalidate();
    }


    /**
     * 服务器白板命令画笔清屏
     */
    public void clearService() {
        //mPathStack.clear();
        mPathStackBackup.clear();
        mGraffitiOrderData.clear();
        initCanvas();
        postInvalidate();
        LogUtil.i("undoServer", "服务器白板命令画笔清屏");
    }


    /**
     * 本地画笔撤销
     */
    public void undo() {
        if (mPathStack.size() > 0) {
            mPathStack.remove(mPathStack.size() - 1);
            initCanvas();
            draw(mBitmapCanvas, mPathStack);
            invalidate();
        }
    }


    /**
     * 服务器白板命令画笔撤销
     */
    public void undoServer (int objid) {
        if (mPathStackBackup.size() > 0) {
            //mPathStackBackup.remove(mPathStackBackup.size() - 1);
            mPathStackBackup.remove(objid+"");
            initCanvas();
            draw(mBitmapCanvas, mPathStackBackup);
            postInvalidate();
            LogUtil.i("undoServer", "服务器白板命令画笔撤销");
        }
    }

    /**
     * 服务器白板命令画笔撤销
     */
    public void undoServer (String objid) {
        if (mPathStackBackup.size() > 0) {
            //mPathStackBackup.remove(mPathStackBackup.size() - 1);
            mPathStackBackup.remove(objid+"");
            initCanvas();
            draw(mBitmapCanvas, mPathStackBackup);
            postInvalidate();
            LogUtil.i("undoServer", "服务器白板命令画笔撤销");
        }
    }

    /**
     * 服务器白板命令画笔轨迹文字的修改
     */
    public void undoTextChangeServer (int objid, String textString) {
        if (mPathStackBackup.size() > 0 && mPathStackBackup.containsKey(objid+"")) {
            GraffitiPath path = mPathStackBackup.get(objid+"");
            path.text = textString;
            mPathStackBackup.put(objid+"", path);
            initCanvas();
            draw(mBitmapCanvas, mPathStackBackup);
            postInvalidate();
            LogUtil.i("undoTextChangeServer", "服务器白板命令画笔轨迹文字的修改");
        }

        for (int i = 0; i < mGraffitiOrderData.size(); i++) {
            GraffitiOrdermsgBean graffitiOrdermsgBean = mGraffitiOrderData.get(i);
            if (graffitiOrdermsgBean.getObjId().equals("objid")) {
                String orderMsg = graffitiOrdermsgBean.getOrderMsg();
                TextWhiteBoardBean textWhiteBoardBean = new Gson().fromJson(orderMsg, TextWhiteBoardBean.class);
                textWhiteBoardBean.getMessage().getWhiteboard().getObjdata().setString(textString);
            }
        }
    }

    /**
     * 清空画板所有内容
     */
    public void clearDraw (){
        mPathStack.clear();
        mPathStackBackup.clear();

        if (mGraffitiBitmap != null) {
            mGraffitiBitmap.recycle();
        }
        //空白画布
        mGraffitiBitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_4444);
        mBitmapCanvas = new Canvas(mGraffitiBitmap);
        postInvalidate();
    }




    /**
     * 获取当前页轨迹路径
     */
    public GraffitiPathPage getGraffitiPathPage() {
        mGraffitiPathPage = new GraffitiPathPage();
        if (null == mWhiteBoardBean || mWhiteBoardBean.getCurrentpage() == 0) {
            mGraffitiPathPage.setCurrentPage(1);
        }else {
            mGraffitiPathPage.setCurrentPage(mWhiteBoardBean.getCurrentpage());
        }

        if (null == mWhiteBoardBean || TextUtils.isEmpty(mWhiteBoardBean.getFileid() + "")){
            mGraffitiPathPage.setFileid(new Random().nextInt() + "-");
        }else {
            mGraffitiPathPage.setFileid(mWhiteBoardBean.getFileid() + "");
        }

        mGraffitiPathPage.setmPathMap(mPathStackBackup);
        LogUtil.i("getGraffitiPathPage", "获取当前页轨迹路径");
        return mGraffitiPathPage;
    }



    /**
     *如果有当前轨迹集合，则恢复轨迹
     */
    public void restoreDrawPath(Map<String, GraffitiPath> graffitiPathMap, String paintMsg) {
        if (null == graffitiPathMap && graffitiPathMap.size() == 0) {
            return;
        }
        mPathStackBackup.clear();
        mPathStackBackup.putAll(graffitiPathMap);

        mGraffitiOrderData.clear();
        if (paintMsg != null && !paintMsg.equals("")) {
            mGraffitiOrderData = new Gson().fromJson(paintMsg, new TypeToken<List<GraffitiOrdermsgBean>>() {}.getType());
        }

        initCanvas();
        draw(mBitmapCanvas, graffitiPathMap);
        postInvalidate();
        LogUtil.i("restoreDrawPath", "恢复轨迹 mPathStackBackup.size() = " + mPathStackBackup.size());
    }



    /**
     * 是否有修改
     */
    public boolean isModified() {
        return mPathStack.size() != 0;
    }

    /**
     * 居中图片
     */
    public void centrePic() {
        mScale = 1;
        // 居中图片
        mTransX = 0;
        mTransY = 0;
        judgePosition();
        invalidate();
    }

    /**
     * 只绘制原图
     *
     * @param justDrawOriginal
     */
    public void setJustDrawOriginal(boolean justDrawOriginal) {
        isJustDrawOriginal = justDrawOriginal;
        invalidate();
    }

    public boolean isJustDrawOriginal() {
        return isJustDrawOriginal;
    }



    /**
     * 设置教师画笔底色
     *
     * @param color
     */
    public void setColorTeacher(int color) {
        mColorTeacher.setColor(color);
        postInvalidate();
    }



    /**
     * 设置本地画笔底色
     *
     * @param color
     */
    public void setColor(int color, String colorStr) {
        mColor.setColor(color);
        this.color = colorStr;
        postInvalidate();
    }

    /**
     * 设置本地画笔底色
     *
     * @param color
     */
    public void setColor(int color) {
        mColor.setColor(color);
        postInvalidate();
    }

    public void setColor(Bitmap bitmap) {
        if (mBitmap == null) {
            return;
        }
        mColor.setColor(bitmap);
        invalidate();
    }

    public void setColor(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY) {
        if (mBitmap == null) {
            return;
        }
        mColor.setColor(bitmap, tileX, tileY);
        invalidate();
    }

    public GraffitiColor getGraffitiColor() {
        return mColor;
    }

    /**
     * 缩放倍数，图片真实的缩放倍数为 mPrivateScale*mScale
     *
     * @param scale
     */
    public void setScale(float scale) {
        this.mScale = scale;
        judgePosition();
        resetMatrix();
        invalidate();
    }

    public float getScale() {
        return mScale;
    }

    /**
     * 设置画笔
     *
     * @param pen
     */
    public void setPen(Pen pen) {
        if (pen == null) {
            throw new RuntimeException("Pen can't be null");
        }
        mPen = pen;
        resetMatrix();
        invalidate();
    }

    public Pen getPen() {
        return mPen;
    }

    /**
     * 设置画笔形状
     *
     * @param shape
     */
    public void setShape(Shape shape) {
        if (shape == null) {
            throw new RuntimeException("Shape can't be null");
        }
        mShape = shape;
        invalidate();
    }

    public Shape getShape() {
        return mShape;
    }

    public void setTrans(float transX, float transY) {
        mTransX = transX;
        mTransY = transY;
        judgePosition();
        resetMatrix();
        invalidate();
    }

    /**
     * 设置图片偏移
     *
     * @param transX
     */
    public void setTransX(float transX) {
        this.mTransX = transX;
        judgePosition();
        invalidate();
    }

    public float getTransX() {
        return mTransX;
    }

    public void setTransY(float transY) {
        this.mTransY = transY;
        judgePosition();
        invalidate();
    }

    public float getTransY() {
        return mTransY;
    }


    public void setPaintSize(float paintSize) {
        mPaintSize = paintSize;
        invalidate();
    }

    public void setPaintSizePost(float paintSize) {
        mPaintSize = paintSize;
        postInvalidate();
    }

    public float getPaintSize() {
        return mPaintSize;
    }

    /**
     * 触摸时，图片区域外是否绘制涂鸦轨迹
     *
     * @param isDrawableOutside
     */
    public void setIsDrawableOutside(boolean isDrawableOutside) {
        mIsDrawableOutside = isDrawableOutside;
    }

    /**
     * 触摸时，图片区域外是否绘制涂鸦轨迹
     */
    public boolean getIsDrawableOutside() {
        return mIsDrawableOutside;
    }

    /**
     * 设置放大镜的倍数，当小于等于0时表示不使用放大器功能
     *
     * @param amplifierScale
     */
    public void setAmplifierScale(float amplifierScale) {
        mAmplifierScale = amplifierScale;
        invalidate();
    }


    /**
     * 设置 图形默认手绘模式
     */
    public void setDrawShapeType(){
        mShape = Shape.HAND_WRITE;
    }


    public float getAmplifierScale() {
        return mAmplifierScale;
    }

    public interface GraffitiListener {

        /**
         * 出错
         *
         * @param i
         * @param msg
         */
        void onError(int i, String msg);

        /**
         * 准备工作已经完成
         */
        void onReady();
    }

    /**
     * 绘制光标指示器
     * @param canvas
     * @param x
     * @param y
     */
    public void drawPosition(Canvas canvas, int x, int y) {
//        mCursorLocation.updateLocation(x, y);
//        mCursorLocation.drawItSelf(canvas);  4-24暂时隐藏
    }

    /**
     * 设置光标位置
     * @param x
     * @param y
     */
    public void setLocation(int x, int y) {
        positionX = x;
        positionY = y;
        postInvalidate();
    }

    /**
     * 提交划线数据
     */
    private void postDrawLineData (int random){
        WhiteBoardBody whiteBoardBody = new WhiteBoardBody();
        WhiteBoardBody.MessageBean messageBean = new WhiteBoardBody.MessageBean();
        messageBean.setType("whiteboard");
        final WhiteBoardBody.MessageBean.WhiteboardBean whiteboardBean =
                new WhiteBoardBody.MessageBean.WhiteboardBean();
        whiteboardBean.setColour(color);
        whiteboardBean.setDocserver(Constant.getDocUrl());
        //whiteboardBean.setFiledir(RandomString.getRandomString());
        try {

            if (null == mWhiteBoardBean || mWhiteBoardBean.getCurrentpage() == 0) {
                whiteboardBean.setCurrentpage(1);
                whiteboardBean.setFiledir(Constant.WHITEBOARDFILEDIR);
            }else {
                whiteboardBean.setCurrentpage(mWhiteBoardBean.getCurrentpage());
                whiteboardBean.setFiledir(mWhiteBoardBean.getFiledir());
            }

            if (null == mWhiteBoardBean || TextUtils.isEmpty(mWhiteBoardBean.getFileid() + "")){
                LogUtil.i("提交划线数据","mWhiteBoardBean.getFileid() = 空 ");
                //Toast.makeText(mContext, "网络中断，请重新进入房间", Toast.LENGTH_SHORT).show();
                return;
            }
            whiteboardBean.setFileid(Integer.valueOf(mWhiteBoardBean.getFileid()));
            whiteboardBean.setFilename(TextUtils.isEmpty(mWhiteBoardBean.getFilename())
                    ? "" : mWhiteBoardBean.getFilename());
        } catch (Exception e) {
            Toast.makeText(mContext, "网络中断，请重新进入教室", Toast.LENGTH_SHORT).show();
        }
        whiteboardBean.setImageurl("");
        whiteboardBean.setLinewidth(3);
        whiteboardBean.setObjid( random );
        if (mShape == Shape.HAND_WRITE){
            whiteboardBean.setObjtype("pen");// 画线
        }else if (mShape == Shape.LINE){
            whiteboardBean.setObjtype("shape");// 画直线
            whiteboardBean.setShapetype("line");
        }else if (mShape == Shape.HOLLOW_OVAL){
            whiteboardBean.setObjtype("shape");// 画圆形
            whiteboardBean.setShapetype("emptyellipse");
        }else if (mShape == Shape.HOLLOW_RECT){
            whiteboardBean.setObjtype("shape");// 画矩形
            whiteboardBean.setShapetype("emptyrect");
        }
        whiteboardBean.setPagenum(mWhiteBoardBean.getPagenum());
        whiteboardBean.setPointcount(XYPath.size());
        whiteboardBean.setSqlid("");
        whiteboardBean.setSubcommand("addobject");

        WhiteBoardBody.MessageBean.WhiteboardBean.RectBean rectBean =
                new WhiteBoardBody.MessageBean.WhiteboardBean.RectBean();
        if (XYPath.size() >=2){
            int top = (int) XYPath.get(0).getY();
            int left = (int) XYPath.get(0).getX();
            int bottom = (int) XYPath.get(0).getY();
            int right = (int) XYPath.get(0).getX();
            for (Coordinates coordinates : XYPath) {
                top = (coordinates.getY() < top) ? (int) coordinates.getY() : top;
                left = (coordinates.getX() < left) ? (int) coordinates.getX() : left;
                bottom = (coordinates.getY() > bottom) ? (int) coordinates.getY() : bottom;
                right = (coordinates.getX() > right) ? (int) coordinates.getX() : right;
            }
            rectBean.setTop(top);
            rectBean.setLeft(left);
            rectBean.setBottom(bottom);
            rectBean.setRight(right);
        }

        List<WhiteBoardBody.MessageBean.WhiteboardBean.ObjdataBean> list = new ArrayList<>();
        WhiteBoardBody.MessageBean.WhiteboardBean.ObjdataBean objdataBean ;
        if (mShape == Shape.HAND_WRITE) {
            for (int i = 0; i < XYPath.size(); i++) {
                objdataBean = new WhiteBoardBody.MessageBean.WhiteboardBean.ObjdataBean();
                objdataBean.setX((int) XYPath.get(i).getX());
                objdataBean.setY((int) XYPath.get(i).getY());
                list.add(objdataBean);
            }
        }

        whiteboardBean.setRect(rectBean);
        whiteboardBean.setObjdata(list);
        messageBean.setWhiteboard(whiteboardBean);
        whiteBoardBody.setMessage(messageBean);

        Gson gson = new Gson();
        final String gsonString = gson.toJson(whiteBoardBody);
        LogUtil.i("上传的画笔", gsonString);
        //LogUtil.i("WhiteboardBean", gson.toJson(mWhiteBoardBean));
        LogUtil.e("上传的画笔", mTeacherCurrentPage + "||" + mAnchor);
        //通过IM发送信息
        ThreadUtils.runOnSubThread(new Runnable() {
            @Override
            public void run() {
                if (whiteboardBean.getCurrentpage() == mTeacherCurrentPage || mRoomType == 1 || mAnchor) {
                    VideoActivity.egine.SendGroupMessage(Constant.WHITEBOARDMSGTYPE, VideoActivity.mGroup, gsonString);
                    FileLogUtils.write("Graffiti Upload: " + gsonString, true);
                }
            }
        });

        if (mPathStackBackup.size() == 0) {
            mGraffitiOrderData.clear();
        } else {
            int size = mGraffitiOrderData.size() - mPathStackBackup.size();

            for (int i = 0; i < size; i++) {
                mGraffitiOrderData.remove(mGraffitiOrderData.size() - 1);
            }
        }

        mGraffitiOrderData.add(new GraffitiOrdermsgBean(String.valueOf(random), "L", gsonString));
    }

    public void storeGraffitiLineData(WhiteBoardBean whiteBoardData){
        WhiteBoardBody whiteBoardBody = new WhiteBoardBody();
        WhiteBoardBody.MessageBean messageBean = new WhiteBoardBody.MessageBean();
        messageBean.setType("whiteboard");
        WhiteBoardBody.MessageBean.WhiteboardBean whiteboardBean =
                new WhiteBoardBody.MessageBean.WhiteboardBean();
        whiteboardBean.setColour(whiteBoardData.getColour());
        whiteboardBean.setDocserver(Constant.getDocUrl());
        whiteboardBean.setFiledir(whiteBoardData.getFiledir());
        whiteboardBean.setCurrentpage(whiteBoardData.getCurrentpage());
        whiteboardBean.setFileid(whiteBoardData.getFileid());
        whiteboardBean.setFilename(whiteBoardData.getFilename());
        whiteboardBean.setPagenum(whiteBoardData.getPagenum());
        whiteboardBean.setImageurl(whiteBoardData.getImageurl());
        whiteboardBean.setLinewidth(whiteBoardData.getLinewidth());
        whiteboardBean.setObjid(whiteBoardData.getObjid());
        whiteboardBean.setObjtype(whiteBoardData.getObjtype());
        whiteboardBean.setShapetype(whiteBoardData.getShapetype());
        whiteboardBean.setPointcount(whiteBoardData.getPointcount());
        whiteboardBean.setSqlid(whiteBoardData.getSqlid());
        whiteboardBean.setSubcommand(whiteBoardData.getSubcommand());

        WhiteBoardBody.MessageBean.WhiteboardBean.RectBean rectBean =
                new WhiteBoardBody.MessageBean.WhiteboardBean.RectBean();

        rectBean.setTop(whiteBoardData.getRect().getTop());
        rectBean.setLeft(whiteBoardData.getRect().getLeft());
        rectBean.setBottom(whiteBoardData.getRect().getBottom());
        rectBean.setRight(whiteBoardData.getRect().getRight());
        whiteboardBean.setRect(rectBean);

        if (whiteBoardData.getObjtype().equals("pen")) {
            List<WhiteBoardBody.MessageBean.WhiteboardBean.ObjdataBean> list = new ArrayList<>();
            WhiteBoardBody.MessageBean.WhiteboardBean.ObjdataBean objdataBean ;
            for (int i = 0; i < whiteBoardData.getObjdata().size(); i++) {
                objdataBean = new WhiteBoardBody.MessageBean.WhiteboardBean.ObjdataBean();
                objdataBean.setX(whiteBoardData.getObjdata().get(i).getX());
                objdataBean.setY(whiteBoardData.getObjdata().get(i).getY());
                list.add(objdataBean);
            }

            whiteboardBean.setObjdata(list);
        }

        messageBean.setWhiteboard(whiteboardBean);
        whiteBoardBody.setMessage(messageBean);
        String gsonString = new Gson().toJson(whiteBoardBody);

        if (mPathStackBackup.size() == 0) {
            mGraffitiOrderData.clear();
        } else {
            int size = mGraffitiOrderData.size() - mPathStackBackup.size();
            for (int i = 0; i < size; i++) {
                mGraffitiOrderData.remove(mGraffitiOrderData.size() - 1);
            }
        }

        mGraffitiOrderData.add(new GraffitiOrdermsgBean(String.valueOf(whiteboardBean.getObjid()), "L", gsonString));
        //Log.e("revoke", "mGraffitiData--o-L:" + mGraffitiOrderData.size());
    }

    public WhiteBoardBean getGraffitiLineData(WhiteBoardBody whiteBoardData){
        WhiteBoardBean whiteBoardBean = new WhiteBoardBean();

        whiteBoardBean.setColour(whiteBoardData.getMessage().getWhiteboard().getColour());
        whiteBoardBean.setDocserver(Constant.getDocUrl());
        whiteBoardBean.setFiledir(whiteBoardData.getMessage().getWhiteboard().getFiledir());
        whiteBoardBean.setCurrentpage(whiteBoardData.getMessage().getWhiteboard().getCurrentpage());
        whiteBoardBean.setFileid(whiteBoardData.getMessage().getWhiteboard().getFileid());
        whiteBoardBean.setFilename(whiteBoardData.getMessage().getWhiteboard().getFilename());
        whiteBoardBean.setPagenum(whiteBoardData.getMessage().getWhiteboard().getPagenum());
        whiteBoardBean.setImageurl(whiteBoardData.getMessage().getWhiteboard().getImageurl());
        whiteBoardBean.setLinewidth(whiteBoardData.getMessage().getWhiteboard().getLinewidth());
        whiteBoardBean.setObjid(whiteBoardData.getMessage().getWhiteboard().getObjid());
        whiteBoardBean.setObjtype(whiteBoardData.getMessage().getWhiteboard().getObjtype());
        whiteBoardBean.setShapetype(whiteBoardData.getMessage().getWhiteboard().getShapetype());
        whiteBoardBean.setPointcount(whiteBoardData.getMessage().getWhiteboard().getPointcount());
        whiteBoardBean.setSqlid(whiteBoardData.getMessage().getWhiteboard().getSqlid());
        whiteBoardBean.setSubcommand(whiteBoardData.getMessage().getWhiteboard().getSubcommand());

        WhiteBoardBean.RectBean rectBean = new WhiteBoardBean.RectBean();

        rectBean.setTop(whiteBoardData.getMessage().getWhiteboard().getRect().getTop());
        rectBean.setLeft(whiteBoardData.getMessage().getWhiteboard().getRect().getLeft());
        rectBean.setBottom(whiteBoardData.getMessage().getWhiteboard().getRect().getBottom());
        rectBean.setRight(whiteBoardData.getMessage().getWhiteboard().getRect().getRight());
        whiteBoardBean.setRect(rectBean);

        if (whiteBoardData.getMessage().getWhiteboard().getObjtype().equals("pen")) {
            List<WhiteBoardBean.ObjdataBean> list = new ArrayList<>();
            WhiteBoardBean.ObjdataBean objdataBean ;
            for (int i = 0; i < whiteBoardData.getMessage().getWhiteboard().getObjdata().size(); i++) {
                objdataBean = new WhiteBoardBean.ObjdataBean();
                objdataBean.setX(whiteBoardData.getMessage().getWhiteboard().getObjdata().get(i).getX());
                objdataBean.setY(whiteBoardData.getMessage().getWhiteboard().getObjdata().get(i).getY());
                list.add(objdataBean);
            }

            whiteBoardBean.setObjdata(list);
        }

        return whiteBoardBean;
    }

    public void storeGraffitiTextData(TextWhiteBoardBean.MessageBean whiteBoardData){

        TextWhiteBoardBean textWhiteBoardBean = new TextWhiteBoardBean();
        textWhiteBoardBean.setMessage(whiteBoardData);
        String gsonString = new Gson().toJson(textWhiteBoardBean);

        if (mPathStackBackup.size() == 0) {
            mGraffitiOrderData.clear();
        } else {
            int size = mGraffitiOrderData.size() - mPathStackBackup.size();
            for (int i = 0; i < size; i++) {
                mGraffitiOrderData.remove(mGraffitiOrderData.size() - 1);
            }
        }

        mGraffitiOrderData.add(new GraffitiOrdermsgBean(String.valueOf(whiteBoardData.getWhiteboard().getObjid()), "T", gsonString));
    }

}
